/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/


#include "stdafx.h"
#include <pgl/core/PGLView2D.h>

PGL_IMPLEMENT_DYNCREATE(CPGLView2D, CPGLViewScreen);

void CPGLView2D::SerializeXML(CPGLArchive& ar)
{
	static const TCHAR szTag[] = _T("CPGLView2D");


	markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup());

	if(ar.IsStoring())
	{
		xml.AddChildElem(szTag);
		xml.IntoElem();
		
			// base class
			CPGLViewScreen::SerializeXML(ar);

			xml.AddChildElemEx(_T("Left"), m_dLeft);
			xml.AddChildElemEx(_T("Right"), m_dRight);
			xml.AddChildElemEx(_T("Top"), m_dTop);
			xml.AddChildElemEx(_T("Bottom"), m_dBottom);
		xml.OutOfElem();
	}
	else
	{
		if  (!xml.FindChildElem(szTag))
				return;

		xml.IntoElem();

			/////////////////////////////////////////////////////////
			// loading base class
			// base class
			CPGLViewScreen::SerializeXML(ar);

			xml.FindGetChildData(_T("Left"), m_dLeft);
			xml.FindGetChildData(_T("Right"), m_dRight);
			xml.FindGetChildData(_T("Top"), m_dTop);
			xml.FindGetChildData(_T("Bottom"), m_dBottom);

		xml.OutOfElem();
	}
}

#ifdef _DEBUG
void CPGLView2D::Dump( CDumpContext& dc ) const
{
    // call base class function first
    CPGLViewScreen::Dump( dc );

    // now do the stuff for our specific class
	// now dumping
	dc <<_T("--- CPGLView2D ---") << "\n";
	dc <<_T("left: ")<<m_dLeft<<
		_T(" right: ")<<m_dRight<<
		_T(" top: ")<<m_dTop<<
		_T(" bottom: ")<<m_dBottom<<"\n";
}

void CPGLView2D::AssertValid() const
{
    // call inherited AssertValid first
    CPGLViewScreen::AssertValid();

    // check CPGLView members...
	ASSERT(m_dLeft<m_dRight);
	ASSERT(m_dBottom<m_dTop);
} 

#endif

CPGLView2D::CPGLView2D(double _dLeft,double _dRight, double _dTop,double _dBottom)
: CPGLViewScreen()
{
	m_dLeft=_dLeft;
	m_dRight=_dRight;
	m_dTop=_dTop;
	m_dBottom=_dBottom;

#pragma warning(push)
#include <yvals.h>              // warning numbers get enabled in yvals.h 
#pragma warning(disable: 4756)
#pragma warning(disable: 4723)

	if ( algotools::IsEqual(m_dBottom,m_dTop) )
	{
		m_dTop+=1;
	}
	if ( algotools::IsEqual(m_dLeft,m_dRight) )
	{
		m_dRight+=1;
	}
#pragma warning(pop)
}

CPGLView2D& CPGLView2D::operator =(const CPGLView2D &v2D)
{
	if (this!=&v2D)
	{
		this->CPGLViewScreen::operator=(v2D);
	
		m_dLeft=v2D.m_dLeft;
		m_dRight=v2D.m_dRight;
		m_dTop=v2D.m_dTop;
		m_dBottom=v2D.m_dBottom;
	}
	return *this;
}

void CPGLView2D::Pan(int x,int y)
{
	double dx=(double)x/m_iWidth*(m_dRight-m_dLeft);
	double dy=(double)y/m_iHeight*(m_dTop-m_dBottom);

	m_dLeft+=dx;
	m_dRight+=dx;
	m_dTop+=dy;
	m_dBottom+=dy;
}

void CPGLView2D::ZoomBox(int xStart,int yStart,int xEnd,int yEnd)
{
	double temp;

	// points orientation
	int xLeft=__min(xStart,xEnd);
	int yUp=__min(yStart,yEnd);
	int dx=abs(xStart - xEnd);
	int dy=abs(yEnd - yStart);
	
	dx=__max(1,dx);
	dy=__max(1,dy);

	temp=(double)(m_dRight-m_dLeft);
	m_dLeft+=temp*(xLeft-m_iTx)/(double)m_iWidth;
	m_dRight=m_dLeft+temp*dx/(double)m_iWidth;
	temp=(double)(m_dTop-m_dBottom);
	m_dTop-=temp*yUp/(double)m_iHeight;
	m_dBottom=m_dTop-temp*dy/(double)m_iHeight;
}

void CPGLView2D::ZoomAll(double _dLeft,double _dRight, double _dBottom, double _dTop)
{
	ASSERT(_dLeft<=_dRight);
	ASSERT(_dBottom<=_dTop);
	
	m_dLeft=_dLeft;
	m_dRight=_dRight;
	m_dTop=_dTop;
	m_dBottom=_dBottom;

}

void CPGLView2D::ZoomScale(double x, double y)
{
	double w=m_dRight-m_dLeft;
	double h=m_dTop-m_dBottom;

	m_dLeft-=(x-1)*w/2.0;
	m_dRight+=(x-1)*w/2.0;
	m_dTop+=(y-1)*h/2.0;
	m_dBottom-=(y-1)*h/2.0;
}

	
void CPGLView2D::ZoomOut()
{
	double w=m_dRight-m_dLeft;
	double h=m_dTop-m_dBottom;

	m_dLeft-=w/4.0;
	m_dRight+=w/4.0;
	m_dTop+=h/4.0;
	m_dBottom-=h/4.0;

}

void CPGLView2D::ZoomIn()
{
	double w=m_dRight-m_dLeft;
	double h=m_dTop-m_dBottom;

	m_dLeft+=w/4.0;
	m_dRight-=w/4.0;
	m_dTop-=h/4.0;
	m_dBottom+=h/4.0;

}

void CPGLView2D::PlotGfx(gfxinterface::CGfxInterface& gfx)
{
	// calling base class
	CPGLViewScreen::PlotGfx(gfx);
	gfx.SetWorldBoundingBox(m_dLeft, m_dBottom, m_dRight, m_dTop);
}

double CPGLView2D::PixelToWorld(int iaxe, int pix)
{
	switch(iaxe)
	{
	case 0:
		ASSERT(m_iWidth > 0);
		return pix*(m_dRight-m_dLeft)/m_iWidth;
		break;
	case 1:
		ASSERT(m_iHeight > 0);
		return pix*(m_dTop-m_dBottom)/m_iHeight;
		break;
	default:
		return 0;
	}
}

double CPGLView2D::PixelToWorldCoord(int iaxe, int pix)
{
	switch(iaxe)
	{
	case 0:
		ASSERT(m_iWidth > 0);
		return m_dLeft+(pix-m_iTx)*(m_dRight-m_dLeft)/m_iWidth;
		break;
	case 1:
		ASSERT(m_iHeight > 0);
		return m_dTop-pix*(m_dTop-m_dBottom)/m_iHeight;
		break;
	default:
		return 0;
	}
}

double CPGLView2D::PixelToWorld(int iaxe, double pix)
{
	switch(iaxe)
	{
	case 0:
		ASSERT(m_iWidth > 0);
		return pix*(m_dRight-m_dLeft)/m_iWidth;
		break;
	case 1:
		ASSERT(m_iHeight > 0);
		return pix*(m_dTop-m_dBottom)/m_iHeight;
		break;
	default:
		return 0;
	}
}

double CPGLView2D::PixelToWorldCoord(int iaxe, double pix)
{
	switch(iaxe)
	{
	case 0:
		ASSERT(m_iWidth > 0);
		return m_dLeft+(pix-m_iTx)*(m_dRight-m_dLeft)/m_iWidth;
		break;
	case 1:
		ASSERT(m_iHeight > 0);
		return m_dTop-pix*(m_dTop-m_dBottom)/m_iHeight;
		break;
	default:
		return 0;
	}
}

